package com.tyros.common.utils;

import com.google.common.collect.Lists;
import com.tyros.common.entity.BaseEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

/**
 * 反射工具类
 *
 * @author zhangshuaiyin
 * @date 2021-06-22 17:05
 */
@SuppressWarnings("unused")
public class ReflectUtils {
    private static final Logger logger = LoggerFactory.getLogger(ReflectUtils.class);
    private static final String SETTER_PREFIX = "set";
    private static final String GETTER_PREFIX = "get";
    private static final String GETTER_PREFIX_BOOL = "is";
    private static final String CGLIB_CLASS_SEPARATOR = "$$";

    private ReflectUtils() {
    }

    /**
     * clazz 类字段名数组
     *
     * @param clazz Class 字节码
     * @return 字段名数组
     */
    public static String[] getFieldArray(Class<?> clazz) {
        Field[] fields = clazz.getDeclaredFields();
        if (fields.length > 0) {
            String[] array = new String[fields.length];

            for (int i = 0; i < fields.length; ++i) {
                array[i] = fields[i].getName();
            }

            return array;
        } else {
            return new String[0];
        }
    }

    /**
     * clazz 类字段名集合
     *
     * @param clazz clazz
     * @return 字段名集合
     */
    public static List<String> getFieldList(Class<?> clazz) {
        Field[] fields = clazz.getDeclaredFields();
        List<String> list = Lists.newArrayList();
        if (fields.length > 0) {
            for (Field f : fields) {
                list.add(f.getName());
            }
        }
        return list;
    }

    /**
     * 获取实体类对应属性（下划线形式）集合
     *
     * @param clazz 实体类
     * @return 属性（下划线形式）集合
     */
    public static List<String> getColumnList(Class<?> clazz) {
        Field[] fields = clazz.getDeclaredFields();
        List<String> list = Lists.newArrayList();
        if (fields.length > 0) {
            for (Field f : fields) {
                list.add(StringUtils.humpToLine(f.getName()));
            }
        }
        return list;
    }

    /**
     * 调用 obj 的 getter 方法
     *
     * @param obj       对象
     * @param fieldName get 方法实参
     * @return getter 方法结果
     */
    public static Object invokeGetter(Object obj, String fieldName) {
        Method method = getter(obj.getClass(), fieldName);

        try {
            if (method != null) {
                return method.invoke(obj);
            }
        } catch (Exception var4) {
            logger.error(String.format("反射调用 %s 报错, 错误信息:%s!", method.getName(), var4.getLocalizedMessage()), var4);
        }
        return null;
    }

    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
        BaseEntity baseEntity = new BaseEntity();
        baseEntity.setId(1L);

        Method id = getter(baseEntity.getClass(), "id");
        System.out.println(id);
        System.out.println(invokeGetter(baseEntity, "id"));
    }

    /**
     * 获取 clazz 类指定属性的 getter 方法
     *
     * @param clazz     类
     * @param fieldName 属性名
     * @return getter 方法
     */
    public static Method getter(Class<?> clazz, String fieldName) {
        char[] chars = fieldName.toCharArray();
        chars[0] = (char) (chars[0] - 32);

        try {
            String getMethodName = GETTER_PREFIX + new String(chars);
            return clazz.getMethod(getMethodName);
        } catch (NoSuchMethodException var6) {
            try {
                String getMethodName = GETTER_PREFIX_BOOL + new String(chars);
                return clazz.getMethod(getMethodName);
            } catch (NoSuchMethodException var5) {
                return null;
            }
        }
    }

    /**
     * 调用 obj 的 setter 方法
     *
     * @param obj       对象
     * @param fieldName set 方法实参
     * @param value     set 值
     */
    public static void invokeSetter(Object obj, String fieldName, Object value) {
        Method method = setter(obj.getClass(), fieldName);

        try {
            if (method != null) {
                method.invoke(obj, value);
            }
        } catch (Exception var5) {
            logger.error(String.format("反射调用 %s 报错, 错误信息:%s!", method.getName(), var5.getLocalizedMessage()), var5);
        }

    }

    /**
     * 获取 clazz 类指定属性的 setter 方法
     *
     * @param clazz     类
     * @param fieldName 属性名
     * @return setter 方法
     */
    public static Method setter(Class<?> clazz, String fieldName) {
        try {
            Class<?>[] parameterTypes = new Class[1];
            Field field = clazz.getDeclaredField(fieldName);
            parameterTypes[0] = field.getType();
            char[] chars = fieldName.toCharArray();
            chars[0] = (char) (chars[0] - 32);
            String methodName = SETTER_PREFIX + new String(chars);
            return clazz.getMethod(methodName, parameterTypes);
        } catch (Exception var6) {
            var6.printStackTrace();
            return null;
        }
    }

    public static Class<?> getClassGenericType(final Class<?> clazz) {
        return getClassGenericType(clazz, 0);
    }

    public static Class<?> getClassGenericType(final Class<?> clazz, final int index) {
        Type genType = clazz.getGenericSuperclass();
        if (!(genType instanceof ParameterizedType)) {
            logger.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType");
            return Object.class;
        } else {
            Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
            if (index < params.length && index >= 0) {
                if (!(params[index] instanceof Class)) {
                    logger.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
                    return Object.class;
                } else {
                    return (Class<?>) params[index];
                }
            } else {
                logger.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: " + params.length);
                return Object.class;
            }
        }
    }
}
